home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / roff.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  22KB  |  1,208 lines

  1. /* roff - text justifier        Author: George L. Sicherman */
  2.  
  3. /*
  4.  *    roff - C version.
  5.  *    the Colonel.  19 May 1983.
  6.  *
  7.  *    Copyright 1983 by G. L. Sicherman.
  8.  *    You may use and alter this software freely for noncommercial ends
  9.  *    so long as you leave this message alone.
  10.  *
  11.  *    Fix by Tim Maroney, 31 Dec 1984.
  12.  *    .hc implemented, 8 Feb 1985.
  13.  *    Fix to hyphenating with underlining, 12 Feb 1985.
  14.  *    Fixes to long-line hang and .bp by Dave Tutelman, 30 Mar 1985.
  15.  *    Fix to centering valve with long input lines, 4 May 1987.
  16.  */
  17.  
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #include <sgtty.h>
  21. #include <signal.h>
  22. #include <stdio.h>
  23.  
  24. #define SUFTAB    "/usr/lib/suftab"
  25. #define TXTLEN    (o_pl-o_m1-o_m2-o_m3-o_m4-2)
  26. #define IDTLEN    (o_ti>=0?o_ti:o_in)
  27. #define MAXMAC    64
  28. #define MAXDEPTH 10
  29. #define MAXLENGTH 255
  30. #define UNDERL    '\200'
  31.  
  32. char cumbuf[BUFSIZ];
  33.  
  34. char spacechars[] = " \t\n";
  35. int sflag, hflag, startpage, stoppage;
  36. char holdword[MAXLENGTH], *holdp;
  37. char assyline[MAXLENGTH];
  38. int assylen;
  39. char ehead[100], efoot[100], ohead[100], ofoot[100];
  40. struct macrotype {
  41.   char mname[3];
  42.   long int moff;
  43. } macro[MAXMAC];
  44. int n_macros;
  45. int depth;
  46. int adjtoggle;
  47. int isrequest = 0;
  48. char o_tr[40][2];        /* OUTPUT TRANSLATION TABLE */
  49. int o_cc = '.';            /* CONTROL CHARACTER */
  50. int o_hc = -1;            /* HYPHENATION CHARACTER */
  51. int o_tc = ' ';            /* TABULATION CHARACTER */
  52. int o_in = 0;            /* INDENT SIZE */
  53. int o_ix = -1;            /* NEXT INDENT SIZE */
  54. int o_ta[20] = {
  55.     9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105,
  56.     113, 121, 129, 137, 145, 153, 161};
  57. int n_ta = 20;            /* #TAB STOPS */
  58. int o_ll = 65, o_ad = 1, o_po = 0, o_ls = 1, o_ig = 0, o_fi = 1;
  59. int o_pl = 66, o_ro = 0, o_hx = 0, o_bl = 0, o_sp = 0, o_sk = 0;
  60. int o_ce = 0, o_m1 = 2, o_m2 = 2, o_m3 = 1, o_m4 = 3, o_ul = 0;
  61. int o_li = 0, o_n1 = 0, o_n2 = 0, o_bp = -1, o_hy = 1;
  62. int o_ni = 1;            /* LINE-NUMBER INDENT */
  63. int o_nn = 0;            /* #LINES TO SUPPRESS NUMBERING */
  64. int o_ti = -1;            /* TEMPORARY INDENT */
  65. int page_no = -1;
  66. int line_no = 9999;
  67. int n_outwords;
  68. FILE *File, *Macread, *Macwrite;
  69. FILE *Save;
  70. long int teller[MAXDEPTH], ftell();
  71. char *strcat(), *strcpy(), *strend(), *strhas();
  72. char *sprintf();
  73. char *request[] = {
  74.        "ad", "ar", "bl", "bp", "br", "cc", "ce", "de",
  75.      "ds", "ef", "eh", "fi", "fo", "hc", "he", "hx", "hy", "ig",
  76.        "in", "ix", "li", "ll", "ls", "m1", "m2", "m3", "m4",
  77.      "n1", "n2", "na", "ne", "nf", "ni", "nn", "nx", "of", "oh",
  78.      "pa", "pl", "po", "ro", "sk", "sp", "ss", "ta", "tc", "ti",
  79.        "tr", "ul", 0};
  80. char *mktemp(), *mfilnam = "/tmp/rtmXXXXXX";
  81. int c;                /* LAST CHAR READ */
  82. struct sgttyb tty;
  83. FILE *fopen();
  84.  
  85. main(argc, argv)
  86. int argc;
  87. char **argv;
  88. {
  89.   if (!isatty(1)) setbuf(stdout, cumbuf);
  90.   while (--argc) switch (**++argv) {
  91.         case '+':    startpage = atoi(++*argv);    break;
  92.         case '-':
  93.         ++*argv;
  94.         if (isdigit(**argv))
  95.             stoppage = atoi(*argv);
  96.         else
  97.             switch (**argv) {
  98.                 case 's':    sflag++;    break;
  99.                 case 'h':    hflag++;    break;
  100.                 default:    bomb();
  101.             }
  102.         break;
  103.         default:
  104.         argc++;
  105.         goto endargs;
  106.     }
  107. endargs:
  108.   if (sflag) ioctl(0, TIOCGETP, &tty);
  109.   mesg(0);            /* BLOCK OUT MESSAGES */
  110.   assylen = 0;
  111.   assyline[0] = '\0';
  112.   if (!argc) {
  113.     File = stdin;
  114.     readfile();
  115.   } else
  116.     while (--argc) {
  117.         File = fopen(*argv, "r");
  118.         if (NULL == File) {
  119.             fprintf(stderr, "roff: cannot read %s\n", *argv);
  120.             exit(1);
  121.         }
  122.         readfile();
  123.         fclose(File);
  124.         argv++;
  125.     }
  126.   writebreak();
  127.   endpage();
  128.   for (; o_sk; o_sk--) blankpage();
  129.   mesg(1);            /* ALLOW MESSAGES */
  130.   exit(0);
  131. }
  132.  
  133. mesg(f)
  134. int f;
  135. {
  136.   static int mode;
  137.   struct stat cbuf;
  138. /* This routine is not needed.
  139.   char *ttyname();
  140.  
  141.   if (!isatty(1)) return;
  142.   if (!f) {
  143.     fstat(1,&cbuf);
  144.     mode = cbuf.st_mode;
  145.     chmod(ttyname(1),mode & ~022);
  146.   }
  147.   else chmod(ttyname(1),mode);
  148. * ------- end of mesg */
  149. }
  150.  
  151. readfile()
  152. {
  153.   while (readline()) {
  154.     if (isrequest) continue;
  155.     if (o_ce || !o_fi) {
  156.         if (assylen)
  157.             writeline(0, 1);
  158.         else
  159.             blankline();
  160.         if (o_ce) o_ce--;
  161.     }
  162.   }
  163. }
  164.  
  165. readline()
  166. {
  167.   int startline, doingword;
  168.   isrequest = 0;
  169.   startline = 1;
  170.   doingword = 0;
  171.   c = suck();
  172.   if (c == '\n') {
  173.     o_sp = 1;
  174.     writebreak();
  175.     goto out;
  176.   } else if (isspace(c))
  177.     writebreak();
  178.   for (;;) {
  179.     if (c == EOF) {
  180.         if (doingword) bumpword();
  181.         break;
  182.     }
  183.     if (c != o_cc && o_ig) {
  184.         while (c != '\n' && c != EOF) c = suck();
  185.         break;
  186.     }
  187.     if (isspace(c) && !doingword) {
  188.         startline = 0;
  189.         switch (c) {
  190.             case ' ':
  191.             assyline[assylen++] = ' ';
  192.             break;
  193.             case '\t':    tabulate();    break;
  194.             case '\n':    goto out;
  195.         }
  196.         c = suck();
  197.         continue;
  198.     }
  199.     if (isspace(c) && doingword) {
  200.         bumpword();
  201.         if (c == '\t')
  202.             tabulate();
  203.         else if (assylen)
  204.             assyline[assylen++] = ' ';
  205.         doingword = 0;
  206.         if (c == '\n') break;
  207.     }
  208.     if (!isspace(c)) {
  209.         if (doingword)
  210.             *holdp++ = o_ul ? c | UNDERL : c;
  211.         else if (startline && c == o_cc && !o_li) {
  212.             isrequest = 1;
  213.             return readreq();
  214.         } else {
  215.             doingword = 1;
  216.             holdp = holdword;
  217.             *holdp++ = o_ul ? c | UNDERL : c;
  218.         }
  219.     }
  220.     startline = 0;
  221.     c = suck();
  222.   }
  223. out:
  224.   if (o_ul) o_ul--;
  225.   if (o_li) o_li--;
  226.   return c != EOF;
  227. }
  228.  
  229. /*
  230.  *    bumpword - add word to current line.
  231.  */
  232.  
  233. bumpword()
  234. {
  235.   char *hc;
  236.   *holdp = '\0';
  237. /*
  238.  *    Tutelman's fix #1, modified by the Colonel.
  239.  */
  240.   if (!o_fi || o_ce) goto giveup;
  241. /*
  242.  *    We use a while-loop in case of ridiculously long words with
  243.  *    multiple hyphenation indicators.
  244.  */
  245.   if (assylen + reallen(holdword) > o_ll - IDTLEN) {
  246.     if (!o_hy)
  247.         writeline(o_ad, 0);
  248.     else
  249.         while (assylen + reallen(holdword) > o_ll - IDTLEN) {
  250. /*
  251.  *    Try hyphenating it.
  252.  */
  253.             if (o_hc && strhas(holdword, o_hc)) {
  254. /*
  255.  *    There are hyphenation marks.  Use them!
  256.  */
  257.                 for (hc = strend(holdword); hc >= holdword; hc--) {
  258.                     if ((*hc & ~UNDERL) != o_hc)
  259.                         continue;
  260.                     *hc = '\0';
  261.                     if (assylen + reallen(holdword) + 1 >
  262.                         o_ll - IDTLEN) {
  263.                         *hc = o_hc;
  264.                         continue;
  265.                     }
  266.  
  267. /*
  268.  *    Yay - it fits!
  269.  */
  270.                     dehyph(holdword);
  271.                     strcpy(&assyline[assylen], holdword);
  272.                     strcat(assyline, "-");
  273.                     assylen += strlen(holdword) + 1;
  274.                     strcpy(holdword, ++hc);
  275.                     break;    /* STOP LOOKING */
  276.                 }    /* for */
  277. /*
  278.  *    It won't fit, or we've succeeded in breaking the word.
  279.  */
  280.                 writeline(o_ad, 0);
  281.                 if (hc < holdword) goto giveup;
  282.             } else {
  283. /*
  284.  *    If no hyphenation marks, give up.
  285.  *    Let somebody else implement it.
  286.  */
  287.                 writeline(o_ad, 0);
  288.                 goto giveup;
  289.             }
  290.         }        /* while */
  291.   }
  292. giveup:
  293. /*
  294.  *    remove hyphenation marks, even if hyphenation is disabled.
  295.  */
  296.   if (o_hc) dehyph(holdword);
  297.   strcpy(&assyline[assylen], holdword);
  298.   assylen += strlen(holdword);
  299.   holdp = holdword;
  300. }
  301.  
  302. /*
  303.  *    dehyph - remove hyphenation marks.
  304.  */
  305.  
  306. dehyph(s)
  307. char *s;
  308. {
  309.   char *t;
  310.   for (t = s; *s; s++)
  311.     if ((*s & ~UNDERL) != o_hc) *t++ = *s;
  312.   *t = '\0';
  313. }
  314.  
  315. /*
  316.  *    reallen - length of a word, excluding hyphenation marks.
  317.  */
  318.  
  319. int reallen(s)
  320. char *s;
  321. {
  322.   register n;
  323.   n = 0;
  324.   while (*s) n += (o_hc != (~UNDERL & *s++));
  325.   return n;
  326. }
  327.  
  328. tabulate()
  329. {
  330.   int j;
  331.   for (j = 0; j < n_ta; j++)
  332.     if (o_ta[j] - 1 > assylen + IDTLEN) {
  333.         for (; assylen + IDTLEN < o_ta[j] - 1; assylen++)
  334.             assyline[assylen] = o_tc;
  335.         return;
  336.     }
  337.  
  338.   /* NO TAB STOPS REMAIN */
  339.   assyline[assylen++] = o_tc;
  340. }
  341.  
  342. int readreq()
  343. {
  344.   char req[3];
  345.   int r, s;
  346.   if (skipsp()) return c != EOF;
  347.   c = suck();
  348.   if (c == EOF || c == '\n') return c != EOF;
  349.   if (c == '.') {
  350.     o_ig = 0;
  351.     do
  352.         (c = suck());
  353.     while (c != EOF && c != '\n');
  354.     if (depth) endmac();
  355.     return c != EOF;
  356.   }
  357.   if (o_ig) {
  358.     while (c != EOF && c != '\n') c = suck();
  359.     return c != EOF;
  360.   }
  361.   req[0] = c;
  362.   c = suck();
  363.   if (c == EOF || c == '\n')
  364.     req[1] = '\0';
  365.   else
  366.     req[1] = c;
  367.   req[2] = '\0';
  368.   for (r = 0; r < n_macros; r++)
  369.     if (!strcmp(macro[r].mname, req)) {
  370.         submac(r);
  371.         goto reqflsh;
  372.     }
  373.   for (r = 0; request[r]; r++)
  374.     if (!strcmp(request[r], req)) break;
  375.   if (!request[r]) {
  376.     do
  377.         (c = suck());
  378.     while (c != EOF && c != '\n');
  379.     return c != EOF;
  380.   }
  381.   switch (r) {
  382.       case 0:            /* ad */
  383.     o_ad = 1;
  384.     writebreak();
  385.     break;
  386.       case 1:            /* ar */    o_ro = 0;    break;
  387.       case 2:            /* bl */
  388.     nread(&o_bl);
  389.     writebreak();
  390.     break;
  391.       case 3:            /* bp */
  392.       case 37:            /* pa */
  393.     c = snread(&r, &s, 1);
  394. /*
  395.  *    Tutelman's fix #2 - the signs were reversed!
  396.  */
  397.     if (s > 0)
  398.         o_bp = page_no + r;
  399.     else if (s < 0)
  400.